﻿using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using System;
using System.Collections.Generic;
using UnityEngine.UI;

public class NoloVR_InputModule : PointerInputModule
{
    public List<NoloVR_SimplePointer> pointers = new List<NoloVR_SimplePointer>();
    protected override void OnEnable()
    {
        //var standaloneInputModule = GetComponent<StandaloneInputModule>();
        //if (standaloneInputModule != null && standaloneInputModule.enabled)
        //{
        //    standaloneInputModule.enabled = false;
        //}
        base.OnEnable();
    }
    
    public override void Process()
    {
        foreach (var pointer in pointers)
        {
            if (pointer.gameObject.activeInHierarchy && pointer.enabled)
            {
                List<RaycastResult> results = new List<RaycastResult>();
                if (pointer.PointerActive())
                {
                    results = CheckRaycasts(pointer);
                }
                //Process events;
                Hover(pointer, results);
                Click(pointer, results);
                Scroll(pointer, results);
            }
        }
    }

    private List<RaycastResult> CheckRaycasts(NoloVR_SimplePointer pointer)
    {
        var raycastResult = new RaycastResult();
        raycastResult.worldPosition = pointer.transform.position;
        raycastResult.worldNormal = pointer.transform.forward;

        pointer.pointerEventData.pointerCurrentRaycast = raycastResult;
        List<RaycastResult> raycasts = new List<RaycastResult>();
        eventSystem.RaycastAll(pointer.pointerEventData, raycasts);
        return raycasts;
    }

    private bool CheckTransformTree(Transform target, Transform source)
    {
        if (target == null)
        {
            return false;
        }

        if (target.Equals(source))
        {
            return true;
        }

        return CheckTransformTree(target.transform.parent, source);
    }

    private bool NoValidCollision(NoloVR_SimplePointer pointer, List<RaycastResult> results)
    {
        return (results.Count == 0 || !CheckTransformTree(results[0].gameObject.transform, pointer.pointerEventData.pointerEnter.transform));
    }

    private bool IsHovering(NoloVR_SimplePointer pointer)
    {
        foreach (var hoveredObject in pointer.pointerEventData.hovered)
        {
            if (pointer.pointerEventData.pointerEnter && hoveredObject && CheckTransformTree(hoveredObject.transform, pointer.pointerEventData.pointerEnter.transform))
            {
                return true;
            }
        }
        return false;
    }

    //private bool ShouldIgnoreElement(GameObject obj, string ignoreCanvasWithTagOrClass, VRTK_TagOrScriptPolicyList canvasTagOrScriptListPolicy)
    //{
    //    var canvas = obj.GetComponentInParent<Canvas>();
    //    if (!canvas)
    //    {
    //        return false;
    //    }

    //    return (Utilities.TagOrScriptCheck(canvas.gameObject, canvasTagOrScriptListPolicy, ignoreCanvasWithTagOrClass));
    //}

    private void Hover(NoloVR_SimplePointer pointer, List<RaycastResult> results)
    {
        if (pointer.pointerEventData.pointerEnter)
        {
            //if (ShouldIgnoreElement(pointer.pointerEventData.pointerEnter, pointer.ignoreCanvasWithTagOrClass, pointer.canvasTagOrScriptListPolicy))
            //{
            //    return;
            //}

            if (NoValidCollision(pointer, results))
            {
                ExecuteEvents.ExecuteHierarchy(pointer.pointerEventData.pointerEnter, pointer.pointerEventData, ExecuteEvents.pointerExitHandler);
                pointer.pointerEventData.hovered.Remove(pointer.pointerEventData.pointerEnter);
                pointer.pointerEventData.pointerEnter = null;
            }
        }
        else
        {
            foreach (var result in results)
            {
                //if (ShouldIgnoreElement(result.gameObject, pointer.ignoreCanvasWithTagOrClass, pointer.canvasTagOrScriptListPolicy))
                //{
                //    continue;
                //}

                var target = ExecuteEvents.ExecuteHierarchy(result.gameObject, pointer.pointerEventData, ExecuteEvents.pointerEnterHandler);
                if (target != null)
                {
                    var selectable = target.GetComponent<Selectable>();
                    if (selectable)
                    {
                        var noNavigation = new Navigation();
                        noNavigation.mode = Navigation.Mode.None;
                        selectable.navigation = noNavigation;
                    }

                    pointer.OnUIPointerElementEnter(pointer.SetUIPointerEvent(target, pointer.hoveringElement));
                    pointer.hoveringElement = target;
                    pointer.pointerEventData.pointerCurrentRaycast = result;
                    pointer.pointerEventData.pointerEnter = target;
                    pointer.pointerEventData.hovered.Add(pointer.pointerEventData.pointerEnter);
                    break;
                }
                else
                {
                    if (result.gameObject != pointer.hoveringElement)
                    {
                        pointer.OnUIPointerElementEnter(pointer.SetUIPointerEvent(result.gameObject, pointer.hoveringElement));
                    }
                    pointer.hoveringElement = result.gameObject;
                }
            }

            if (pointer.hoveringElement && results.Count == 0)
            {
                pointer.OnUIPointerElementExit(pointer.SetUIPointerEvent(null, pointer.hoveringElement));
                pointer.hoveringElement = null;
            }
        }
    }
    private void Click(NoloVR_SimplePointer pointer, List<RaycastResult> results)
    {
#if NOLO_3DOF
        pointer.pointerEventData.eligibleForClick = NoloVR_Controller.GetDevice(pointer.deviceType).GetNoloButtonUp(NoloButtonID.Trigger)||Input.GetMouseButtonUp(0);
#elif NOLO_6DOF
        pointer.pointerEventData.eligibleForClick = NoloVR_Controller.GetDevice(pointer.deviceType).GetNoloButtonUp(NoloButtonID.Trigger)||Input.GetMouseButtonUp(0);
#else
        pointer.pointerEventData.eligibleForClick = Input.GetMouseButtonUp(0);
#endif
        if (pointer.pointerEventData.pointerPress)
        {
            //if (ShouldIgnoreElement(pointer.pointerEventData.pointerPress, pointer.ignoreCanvasWithTagOrClass, pointer.canvasTagOrScriptListPolicy))
            //{
            //    return;
            //}
            if (pointer.pointerEventData.eligibleForClick)
            {
                if (!IsHovering(pointer))
                {
                    ExecuteEvents.ExecuteHierarchy(pointer.pointerEventData.pointerPress, pointer.pointerEventData, ExecuteEvents.pointerUpHandler);
                    pointer.pointerEventData.pointerPress = null;
                }
            }
            else
            {
                ExecuteEvents.ExecuteHierarchy(pointer.pointerEventData.pointerPress, pointer.pointerEventData, ExecuteEvents.pointerClickHandler);
                ExecuteEvents.ExecuteHierarchy(pointer.pointerEventData.pointerPress, pointer.pointerEventData, ExecuteEvents.pointerUpHandler);
                pointer.pointerEventData.pointerPress = null;
            }
        }
        else if (pointer.pointerEventData.eligibleForClick)
        {
            foreach (var result in results)
            {
                //if (ShouldIgnoreElement(result.gameObject, pointer.ignoreCanvasWithTagOrClass, pointer.canvasTagOrScriptListPolicy))
                //{
                //    continue;
                //}

                var target = ExecuteEvents.ExecuteHierarchy(result.gameObject, pointer.pointerEventData, ExecuteEvents.pointerDownHandler);
                if (target != null)
                {
                    pointer.pointerEventData.pressPosition = pointer.pointerEventData.position;
                    pointer.pointerEventData.pointerPressRaycast = result;
                    pointer.pointerEventData.pointerPress = target;
                    break;
                }
            }
        }
    }
    private void Scroll(NoloVR_SimplePointer pointer, List<RaycastResult> results)
    {
        //pointer.pointerEventData.scrollDelta = NoloVR_Controller.GetDevice(pointer.deviceType).GetAxis(NoloTouchID.TouchPad);
        //var scrollWheelVisible = false;
        //foreach (RaycastResult result in results)
        //{
        //    if (pointer.pointerEventData.scrollDelta != Vector2.zero)
        //    {
        //        var target = ExecuteEvents.ExecuteHierarchy(result.gameObject, pointer.pointerEventData, ExecuteEvents.scrollHandler);
        //        if (target)
        //        {
        //            scrollWheelVisible = true;
        //        }
        //    }
        //}
    }

    protected override void OnDisable()
    {
        var standaloneInputModule = GetComponent<StandaloneInputModule>();
        if (standaloneInputModule != null && standaloneInputModule.enabled == false)
        {
            standaloneInputModule.enabled = true;
        }
        base.OnDisable();
    }
}
